package ru.agiledev.akb.server.logic;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import ru.agiledev.akb.server.domain.*;
import ru.agiledev.akb.server.domain.presentation.Addition;
import ru.agiledev.akb.server.domain.presentation.Author;
import ru.agiledev.akb.server.domain.presentation.History;
import ru.agiledev.akb.server.domain.presentation.Page;
import ru.agiledev.akb.server.hibernate.HibernateUtil;
import ru.agiledev.akb.shared.QType;
import ru.agiledev.akb.shared.TransferObject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by a.kirillov
 * Date: 5/10/11 Time: 10:07 PM
 */
public class DataManager {
    //just saving newly created entry
    //TODO: saving in phase of editing
    public static void saveEntry(TransferObject dto){
        //TODO: interconnection of existing objects
        Question question = new Question(dto.question);

        QType type = dto.questionType;

        Session session = HibernateUtil.getSessionFactory().openSession();
        Criteria criteria = session.createCriteria(IObject.class);

        List<IObject> interestObjs = new ArrayList<IObject>(dto.iObjects.length-1);
        List<IObject> iObjects = new ArrayList<IObject>(dto.iObjects.length);


        List<Serializable> newAspects = new ArrayList<Serializable>();
        List<Serializable> newExamples = new ArrayList<Serializable>();

        for(String iObject:dto.iObjects){

            List<IObject> list = criteria.add(Restrictions.eq("value", iObject.trim())).list();

            if(list.size()==0){

                if(iObject.length()>0) iObjects.add(new IObject(iObject));

            } else {
                if(iObject.length()>0) iObjects.add(list.get(0));
            }
        }

        interestObjs.add(iObjects.get(1));
        if(iObjects.size()==3){
            interestObjs.add(iObjects.get(2));
        }


        List<Aspect> aspects = new ArrayList<Aspect>(dto.aspects.length);

        criteria = session.createCriteria(Aspect.class);

        for(String aspect:dto.aspects){

            List<Aspect> list = criteria.add(Restrictions.eq("value", aspect.trim())).add(Restrictions.eq("type", type)).list();

            if(list.size()==0){
                Aspect a = new Aspect(aspect.trim());
                a.setType(type);
                aspects.add(a);
            } else {
                aspects.add(list.get(0));
            }
        }

        List<Example> examples = new ArrayList<Example>(dto.examples.length);
        criteria = session.createCriteria(Example.class);

        for(String example:dto.examples){
            List<Example> list = criteria.add(Restrictions.eq("value", example.trim())).list();

            if(list.size()==0){
            examples.add(new Example(example.trim()));
            } else {
                examples.add(list.get(0));
            }
        }

        //TODO: сохраняем сущности по-отдельности
        session.beginTransaction();


        for(Aspect aspect:aspects){
            aspect.setiObjects(interestObjs);
            Serializable id = session.save(aspect);
            newAspects.add(id);
        }

        session.getTransaction().commit();
        session.beginTransaction();

        for(IObject iObject:iObjects){
            if(hasElement(interestObjs, iObject)){
                iObject.setAspects(aspects);
            }

            List<Question> questions = iObject.getQuestions();
            if(questions==null){
                questions = new ArrayList<Question>();
            }
            questions.add(question);
            iObject.setQuestions(questions);
            session.save(iObject);
        }

        session.getTransaction().commit();
        session.beginTransaction();

        for(Example example:examples){
            example.setQuestion(question);
            Serializable id = session.save(example);
            newExamples.add(id);
        }

        question.setExamples(examples);
        question.setType(type);
        question.setiObjects(iObjects);

        session.save(question);

        session.getTransaction().commit();

        session.close();
        //TODO: привязываем к презентационному слою

        session = HibernateUtil.getSessionFactory().openSession();
        criteria = session.createCriteria(Author.class);

        List<Author> list = criteria.add(Restrictions.eq("id", dto.getUser().getId())).list();
        Author author = list.get(0);

        History history = author.getHistory();

        List<Page> pages = history.getCreatedPages();

        if(pages == null){
            pages = new ArrayList<Page>();
        }

        Page page = new Page();
        page.setQuestion(question);

        List<Aspect> alst = new ArrayList<Aspect>();
        List<Example> elst = new ArrayList<Example>();

        for(Serializable id:newAspects){
            List<Aspect> al = session.createCriteria(Aspect.class).add(Restrictions.eq("id", id)).list();
            if(al.size()>0){
                alst.add(al.get(0));
            }
        }

        page.setAspects(alst);

        for(Serializable id:newExamples){
            List<Example> al = session.createCriteria(Example.class).add(Restrictions.eq("id", id)).list();
            if(al.size()>0){
                elst.add(al.get(0));
            }
        }

        page.setExamples(elst);

        pages.add(page);
        history.setCreatedPages(pages);

        session.beginTransaction();

        session.save(page);
        session.save(history);
        session.getTransaction().commit();
        session.close();
    }

    public static void updateEntry(TransferObject dto){
        //TODO: update aspects and examples
        Session session = HibernateUtil.getSessionFactory().openSession();
        List<Question> list = session.createCriteria(Question.class).add(Restrictions.eq("value", dto.getQuestion().trim())).add(Restrictions.eq("type", dto.getQuestionType())).list();

        if(list.size()>0){
            Question question = list.get(0);
            int qId = question.getId();

            List<IObject> iObjects = question.getiObjects();

            List<Example> examples = question.getExamples();

            List<Serializable> newAspects = new ArrayList<Serializable>();
            List<Serializable> newExamples = new ArrayList<Serializable>();

            session.beginTransaction();

            for(IObject obj:iObjects){
                if(obj.getAspects().size()>0){
                    String[] asps = dto.getAspects();
                    List<Aspect> oAspects = obj.getAspects();
                    for(String asp:asps){
                        Aspect a = new Aspect(asp.trim());
                        a.setType(dto.getQuestionType());

                        if(!hasElement(oAspects, a)){

                            Serializable id = session.save(a);
                            newAspects.add(id);
                            obj.getAspects().add(a);
                            session.update(obj);
                        }
                    }

                }
            }


            String[] exmpls = dto.getExamples();
            for(String ex:exmpls){
                Example a = new Example(ex.trim());
                a.setQuestion(question);
                if(!hasElement(examples, a)){
                    Serializable id = session.save(a);
                    newExamples.add(id);
                    question.getExamples().add(a);
                    session.update(question);
                }
            }

            session.getTransaction().commit();
            session.close();

        //Presentation layer update

        session = HibernateUtil.getSessionFactory().openSession();
        Criteria criteria = session.createCriteria(Author.class);

        List<Author> aList = criteria.add(Restrictions.eq("id", dto.getUser().getId())).list();
        Author author = aList.get(0);

        History history = author.getHistory();

        if(history.getAdditions() == null){
            history.setAdditions(new ArrayList<Addition>());
        }

        Addition addition = new Addition();

            List<Question> q = session.createCriteria(Question.class).add(Restrictions.eq("id", qId)).list();

            if(q.size()>0){
                question = q.get(0);

                List<Page> pList = session.createCriteria(Page.class).add(Restrictions.eq("question", question)).list();

                if(pList.size()>0){
                    Page page = pList.get(0);
                    List<Aspect> alst = new ArrayList<Aspect>();
                    List<Example> elst = new ArrayList<Example>();

                    for(Serializable id:newAspects){
                        List<Aspect> al = session.createCriteria(Aspect.class).add(Restrictions.eq("id", id)).list();
                        if(al.size()>0){
                            alst.add(al.get(0));
                        }
                    }

                    addition.setAspects(alst);

                    for(Serializable id:newExamples){
                        List<Example> al = session.createCriteria(Example.class).add(Restrictions.eq("id", id)).list();
                        if(al.size()>0){
                            elst.add(al.get(0));
                        }
                    }

                    addition.setExamples(elst);
                    addition.setPage(page);
                }
            }

            session.beginTransaction();

            session.save(addition);
            history.getAdditions().add(addition);
            session.save(history);

            session.getTransaction().commit();
            session.close();
        }
    }


    public static TransferObject getDataForQuestion(String question){
        Session session = HibernateUtil.getSessionFactory().openSession();
        List<Question> list = session.createCriteria(Question.class).add(Restrictions.eq("value", question)).list();

        if(list.size()>0){
            Question q = list.get(0);

            TransferObject dto = new TransferObject();
            dto.setQuestion(q.getValue());
            dto.setQuestionType(q.getType());

            List<IObject> iObjects = q.getiObjects();
            List<String> objectsStr = new ArrayList<String>();
            List<String> examplesStr = new ArrayList<String>();
            List<String> aspectsStr = new ArrayList<String>();

            for(IObject obj:iObjects){
                objectsStr.add(obj.getValue());

                List<Aspect> asps = obj.getAspects();
                if((asps!=null)&&(asps.size()>0)){
                    for(Aspect asp:asps){
                        if(!aspectsStr.contains(asp.getValue())){
                            aspectsStr.add(asp.getValue());
                        }
                    }
                }
            }

            List<Example> examples = q.getExamples();
            for(Example exmpl:examples){
                examplesStr.add(exmpl.getValue());
            }

            dto.setAspects(toStringArray(aspectsStr.toArray()));
            dto.setExamples(toStringArray(examplesStr.toArray()));
            dto.setiObjects(toStringArray(objectsStr.toArray()));

            session.close();
            return dto;
        }

        session.close();
        return null;
    }

    public static TransferObject getDataForQuestion(Integer id){
        Session session = HibernateUtil.getSessionFactory().openSession();
        List<Question> list = session.createCriteria(Question.class).add(Restrictions.eq("id", id)).list();

        if(list.size()>0){
            Question q = list.get(0);

            TransferObject dto = new TransferObject();
            dto.setQuestion(q.getValue());
            dto.setQuestionType(q.getType());

            List<IObject> iObjects = q.getiObjects();
            List<String> objectsStr = new ArrayList<String>();
            List<String> examplesStr = new ArrayList<String>();
            List<String> aspectsStr = new ArrayList<String>();

            for(IObject obj:iObjects){
                objectsStr.add(obj.getValue());

                List<Aspect> asps = obj.getAspects();
                if((asps!=null)&&(asps.size()>0)){
                    for(Aspect asp:asps){
                        if(!aspectsStr.contains(asp.getValue())){
                            aspectsStr.add(asp.getValue());
                        }
                    }
                }
            }

            List<Example> examples = q.getExamples();
            for(Example exmpl:examples){
                examplesStr.add(exmpl.getValue());
            }

            dto.setAspects(toStringArray(aspectsStr.toArray()));
            dto.setExamples(toStringArray(examplesStr.toArray()));
            dto.setiObjects(toStringArray(objectsStr.toArray()));

            session.close();
            return dto;
        }

        session.close();
        return null;
    }

    static String[] toStringArray(Object[] oArray){
        String[] stringArray = new String[oArray.length];
        for (int i = 0; i < oArray.length; i++) {
            stringArray[i] = oArray[i].toString();
        }

        return stringArray;
    }

    static boolean hasElement(List<? extends AKBEntity> list, AKBEntity o){
        for(AKBEntity e:list){
            if(e.getValue().equals(o.getValue().trim())){
                return true;
            }
        }
        return false;
    }
}
